package com.bid.base.common.util.auth;

import com.alibaba.fastjson.JSONObject;
import com.bid.base.common.anno.PcDecrypt;
import com.bid.base.common.cache.CacheTemplateService;
import com.bid.base.common.entity.CommonEnums;
import com.bid.base.common.entity.OctoSub;
import com.bid.base.common.entity.OctoToken;
import com.bid.base.common.feign.FeignAssistant;
import com.bid.base.common.response.ApiResult;
import com.bid.base.common.response.ErrorCode;
import com.bid.base.common.util.CommonHttp;
import com.bid.base.common.util.JWTUtils;
import com.bid.base.common.util.Stringer;
import com.bid.base.common.util.auth.ext.AuthCustomInterface;
import com.bid.base.common.util.sm4.Sm4Util;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.ExpiredJwtException;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.redisson.api.RBucket;
import org.redisson.api.RedissonClient;
import org.slf4j.MDC;
import org.springframework.aop.aspectj.MethodInvocationProceedingJoinPoint;
import org.springframework.aop.framework.ReflectiveMethodInvocation;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.net.URLDecoder;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;

import static com.bid.base.common.util.CommonHttp.requestSucc;

/**
 * <strong>Description : </strong> <br>
 * <p>
 * <strong>北京正源德标科技信息有限责任公司</strong> <br>
 * </p>
 * <br>
 *
 * @author : zhaots
 * @date Date : 2021年04月07日 14:25
 * 修改人 修改日期 修改描述<br>
 * -------------------------------------------<br>
 * <br>
 * <br>
 */
@Slf4j
public class AuthAssistant {

    public static String TONKEN_KEY_IN_HEADER = "Authorization";

    public static String USER_ID_KEY_IN_HEADER = "User-Id-In-Header";

    public static String MAINTAINER_KEY_IN_HEADER = "Maintainer_Key_In_Header";


    public static final String AUTH_CODE = "AUTH_CODE";

    public static final String EXCEPTION_OBJ = "EXCEPTION_OBJ";

    public static final String EXCEPTION_MSG = "EXCEPTION_MSG";

    public static final String NEED_REFRESH_TOKEN = "NEED_REFRESH_TOKEN";

    public static final String octoRedisPreffix = "OCTO";

    public static final Long DEFAULT_EXPIRE_TIME = 3600000L;

    public static final String ORIGIN = "ORIGIN";

//    public static final String MOCK_LOGIN = "MOCK_LOGIN";

//    public static final String SWITCH_SUBJECT_ID = "SWITCH_SUBJECT_ID";

    public static final String SUBJECT_TYPE = "SUBJECT_TYPE";


//    public static final String REFRESH_TOKEN = "refresh_token";

    public static final String OCTO_ID = "octoid";

    public static final String SUB_SYS = "subSys";

    public static final String SECRET_JSON = "secret";
    public static final String CODE_JSON = "code";
    public static final String GRANT_TYPE_JSON = "grant_type";
    public static final String LOGIN_RANDOMSTR_JSON = "loginRandomStr";
    // "subjectType"
    public static final String USERNAME_JSON = "userName";
    public static final String SUBJECT_TYPE_JSON = "subjectType";

    public static void changedAuthStatus(RedissonClient redissonClient,String userId){
        CommonEnums.ToKenScopeAndLimit[] values = CommonEnums.ToKenScopeAndLimit.values();
        for (CommonEnums.ToKenScopeAndLimit each : values) {
            Object o = getLocalOctoToken(redissonClient, userId, each.getScope(), octoRedisPreffix);
            if(Stringer.isNullOrEmpty(o)){
                continue;
            }
            OctoToken octoToken = (OctoToken)o;
            octoToken.setAuthStatusChanged(CommonEnums.Done.done.ordinal());
            String tokenKey = getTokenKeyInRedis(userId,  each.getScope(), octoRedisPreffix);
            RBucket<Object> bucket = redissonClient.getBucket(tokenKey);
            log.info("changedAuthStatus 存入redis的值： octoToken {}", JSONObject.toJSON(octoToken));
            bucket.set(octoToken, DEFAULT_EXPIRE_TIME, TimeUnit.MILLISECONDS);
        }
    }



    public static boolean isAuthTool(Object scope) {
        if (Stringer.isNullOrEmpty(scope)) {
            return false;
        }
        CommonEnums.ToKenScopeAndLimit parse = CommonEnums.ToKenScopeAndLimit.parseOf(scope.toString());
        if (Stringer.isNullOrEmpty(parse)) {
            return false;
        }
        return true;
    }



    public static Object aroundWrapper(ProceedingJoinPoint joinPoint, String jwtSecret, RedissonClient redissonClient, BigDecimal warningVlaue, String octoid, String refreshTokenUrl, String sm4Httpkey) throws Throwable {
        return aroundWrapper(joinPoint, jwtSecret, redissonClient, warningVlaue, octoid, refreshTokenUrl, sm4Httpkey, null);
    }







    private static Object innerInvokeInPcBeak(PcDecrypt pcDecryptAnno, HttpServletRequest request, String sm4Httpkey, String requestURI, HttpServletResponse response, ProceedingJoinPoint joinPoint) throws Throwable{
        if(!Stringer.isNullOrEmpty(pcDecryptAnno)){
            String serverAuth = request.getHeader(FeignAssistant.RPC_VUE_NOAUTH_KEY);
            if(!Stringer.isNullOrEmpty(serverAuth)) {
                try {
                    boolean b = FeignAssistant.noParamCheck(serverAuth, sm4Httpkey);
                    if(!b){
                        serviceError(ErrorCode.ERROR.getStatus(),"服务之间调用校验失败",requestURI,null,request,response);
                        return true;
                    }
                } catch (Exception e) {
                    serviceError(ErrorCode.ERROR.getStatus(),"校验服务之间凭证异常失败",requestURI,e,request,response);
                    return true;
                }
                try {
//                        log.info("服务之间凭证 {} 认证成功！，放行", serverAuth);
                    return joinPoint.proceed();
                } catch (Exception e) {
                    serviceError(ErrorCode.ERROR.getStatus(), "发现业务方法抛出异常", requestURI, e, request, response);
                    return true;
                }
            }else{
                serviceError(ErrorCode.ERROR.getStatus(), "获取标识值出现异常,应该放的时候出问题了", requestURI, null, request, response);
                return true;
            }
        }
        return false;
    }

    /**
     * 北京正源德标科技信息有限责任公司
     * @params  [joinPoint, jwtSecret, redissonClient, warningVlaue, octoid, refreshTokenUrl, sm4Httpkey, authCustom]
     * @return   java.lang.Object
     * @创建时间 2021/8/16
     * @创建人 zhaots
     * @描述
     *  //可能是定时任务 2018 12 3
     *  if (null == servletRequestAttributes) {
     *      Object result = joinPoint.proceed();
     *         return result;
     *    }
     *    第一个判断：不是Boolean return
     *    第二个判断： //是resone 且true return
     */
    public static Object aroundWrapper(ProceedingJoinPoint joinPoint, String jwtSecret, RedissonClient redissonClient, BigDecimal warningVlaue, String octoid, String refreshTokenUrl, String sm4Httpkey, AuthCustomInterface authCustom) throws Throwable {
        warningVlaue = new BigDecimal("0.5");
        ServletRequestAttributes servletRequestAttributes = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes());
        HttpServletRequest request = servletRequestAttributes.getRequest();
        Method method = getMethod(joinPoint);
        String requestURI = request.getRequestURI();
        NoAuth annotation = method.getAnnotation(NoAuth.class);
        PcDecrypt pcDecryptAnno = method.getAnnotation(PcDecrypt.class);
        HttpServletResponse response = servletRequestAttributes.getResponse();
        log.info("request check auth aop {},method信息：{}", requestURI,method);
        Object resone = innerInvokeInPcBeak(pcDecryptAnno, request, sm4Httpkey, requestURI, response, joinPoint);
        if(!(resone instanceof Boolean)){
            return  resone;
        }
        if((Boolean)resone){
            return null;
        }
        //临时方案
        if (!Stringer.isNullOrEmpty(pcDecryptAnno) ) {
            try {
                return joinPoint.proceed();
            } catch (Exception e) {
                log.error("放过pcDecryptAnno, 公共模块判断无权访问：1：noAuth注解对不对 ,原因2,没有权限，或者传的header里面的token格式不对Bear token 3.注意 octo.jwt.secret e:{}", e);
                serviceError(ErrorCode.ERROR.getStatus(),"发现业务方法抛出异常",requestURI,e,request,response);
                return null;
            }
        }
        //临时方案
        //其他的放行 不需要权限验证也放行
        if (!Stringer.isNullOrEmpty(annotation) ) {
            try {
                return joinPoint.proceed();
            } catch (Exception e) {
                log.error("公共模块判断无权访问：1：noAuth注解对不对 ,原因2,没有权限，或者传的header里面的token格式不对Bear token 3.注意 octo.jwt.secret e:{}", e);
                serviceError(ErrorCode.ERROR.getStatus(),"发现业务方法抛出异常",requestURI,e,request,response);
                return null;
            }
        }
        String auth = null;String token = null;Claims claims = null;
        try {
            auth = request.getHeader(AuthAssistant.TONKEN_KEY_IN_HEADER);
            token = auth.split(" ")[1];
        } catch (Exception e) {
            serviceError(ErrorCode.NO_LOGIN_TIME_OUT.getStatus(),"公共模块判断无权访问：传的header里面的token格式不对：Bear token",requestURI,e,request,response);
            return null;
        }
        String userIdInHeader = request.getHeader(AuthAssistant.USER_ID_KEY_IN_HEADER);

        try {
            //USER_ID_KEY_IN_HEADER TONKEN_KEY_IN_HEADER  必填，不然参数错误
            if (Stringer.isNullOrEmpty(auth,userIdInHeader) || Stringer.isNullOrEmpty(token) || token.length() < 20 || userIdInHeader.length() < 5) {
                serviceError(ErrorCode.ILLEGAL_LOGIN.getStatus(), "参数异常-非法登录--注意token 和 User-Id-In-Header", requestURI, null, request, response);
                return null;
            }
            claims = JWTUtils.parseJWT(token, jwtSecret);
        } catch (Exception e) {
            serviceError(ErrorCode.NO_LOGIN_TIME_OUT.getStatus(), "公共模块判断为no,1：noAuth注解2,token格式 3.octo.jwt.secret,4.过期", requestURI, e, request, response);
            return null;
        }
        String scope = claims.getIssuer();
        //不是认证中心发布的，返回
        if (Stringer.isNullOrEmpty(scope)) {
            log.warn("发布者不对,即scope不对");
            request.getRequestDispatcher(CommonEnums.NO_LOGIN_URL).forward(request, response);
            return null;
        }
        String userId = claims.getSubject();
        //2022-4-7
        if(!(userIdInHeader.trim()).equals(userId)){
            serviceError(ErrorCode.ILLEGAL_LOGIN.getStatus(), "非法登录-userIdInheader和当前token中的userid不一致", requestURI, null, request, response);
            return null;
        }
        Object o = getLocalOctoToken(redissonClient, userId, scope, octoRedisPreffix);
        if (Stringer.isNullOrEmpty(o)) {
            log.warn("没有在redis找到token信息,1：业务和注册中心连接的不是一个redis 2.redis中key的前缀不对");
            request.getRequestDispatcher(CommonEnums.NO_LOGIN_URL).forward(request, response);
            return null;
        }
        OctoToken octoToken = (OctoToken) o;
        Integer changed = octoToken.getAuthStatusChanged();
        //TODO...
        if(!Stringer.isNullOrEmpty(changed) && changed==CommonEnums.Done.done.ordinal()){
            serviceError(ErrorCode.AUTH_STATUS_CHANGED.getStatus(), "权限发生变化需要重新登录", requestURI, null, request, response);
            return null;
        }
        if (!haveAuth(request, claims, octoToken, token)) {
            log.warn("无权限返回");
            request.getRequestDispatcher(CommonEnums.NO_LOGIN_URL).forward(request, response);
            return null;
        }
        log.info("自定义权限拦截判定:有权限 go on");
        //检查是否有自定义权限拦截
        if ((null != authCustom) && (!authCustom.haveAuth(request, claims))) {
            log.info("自定义权限拦截判定为 [无权限] 返回");
            request.getRequestDispatcher(CommonEnums.NO_LOGIN_URL).forward(request, response);
            return null;
        }
        Object result = null;
        try {
            result = joinPoint.proceed();
        } catch (Exception e) {
            serviceError(ErrorCode.ERROR.getStatus(), "业务方法本身的异常请自己处理", requestURI, e, request, response);
            return null;
        }
        //是否需要刷新redis token
        if (requestURI.indexOf("logout") == -1) {

            Object refreshToken = needRefresh(claims, octoToken, warningVlaue, octoid, refreshTokenUrl, sm4Httpkey, redissonClient, octoRedisPreffix);
            if (!Stringer.isNullOrEmpty(refreshToken)) {
                if(result instanceof ApiResult){
                    ApiResult res = (ApiResult) result;
                    res.setStatus(ErrorCode.TOKEN_REFRESH.getStatus());
                    res.setMsg(refreshToken.toString());
                }else{
                    request.setAttribute(NEED_REFRESH_TOKEN, refreshToken.toString());
                }
            }


        }
        try {
            MDC.clear();
        } catch (Exception e) {
            log.error("MDC.clear()异常，先不影响主程序，继续  异常信息：{}", e);
        }
        return result;
    }

    private static void serviceError(Integer authCode,String errMsg, String requestURI, Exception e, HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        log.error("requestURI：{},errMsg:{},e:{}", errMsg, requestURI, e);
        request.setAttribute(EXCEPTION_OBJ, e);
        request.setAttribute(EXCEPTION_MSG, errMsg);
        request.setAttribute(AUTH_CODE, authCode);
        request.getRequestDispatcher(CommonEnums.NO_LOGIN_URL).forward(request, response);
    }


    /**
     * String key=CommonEnums.colove_wechat_redis_preffix+encodeUsername;
     * <p>
     * stringRedisTemplate.opsForValue().set(key, JSONObject.toJSONString(userDb),12,TimeUnit.HOURS);
     * <p>
     * CookieHelper.setCookie(response,Constant.LOGIN_COOKIE_NAME,encodeUsername);
     *
     * @return
     * @throws Exception
     */
    public static boolean haveAuth(HttpServletRequest request, Claims claims, OctoToken octoToken,String token) {
        try {
            Object refreshTokenFlag = claims.get(CommonEnums.REFRESH_TOKEN_FLAG);
            if (!Stringer.isNullOrEmpty(refreshTokenFlag)) {
                log.warn("不能用refretoken");
                return false;
            }
            //不是认证中心发布的，返回TODO
            String scope = claims.getIssuer();
            String userId = claims.getSubject();
            String govExpertId = claims.get(CommonEnums.MdcKey.GOV_EXPERT_ID.getName()).toString();
            String randomStr = claims.get(CommonEnums.MdcKey.L_RANDOM_STR.getName()).toString();
            String name = claims.get(CommonEnums.MdcKey.NAME.getName()).toString();
            String deptId = claims.get(CommonEnums.MdcKey.DEPT_ID.getName()).toString();
            String userName = claims.get(CommonEnums.MdcKey.USER_NAME.getName()).toString();
            String subjectType = claims.get(CommonEnums.MdcKey.SUBJECT_TYPE.getName()).toString();
            String legalId = claims.get(CommonEnums.MdcKey.LEGAL_ID.getName()).toString();
            String loginTid = claims.get(CommonEnums.MdcKey.ZZHLCA_LOGIN_TID.getName()).toString();
            String capacityType = claims.get(CommonEnums.MdcKey.CAPACITY_TYPE.getName()).toString();
            String loginType = claims.get(CommonEnums.MdcKey.LOGIN_TYPE.getName()).toString();

            String sdeptCode = claims.get(CommonEnums.MdcKey.SURVEILLANCE_DEPT_CODE.getName()).toString();
            String sdeptName = claims.get(CommonEnums.MdcKey.SURVEILLANCE_DEPT_NAME.getName()).toString();
            //如果 从claims里面获取的 dockingSystemCode 是空，那么 应该从request里面获取
            String dockingSystemCode = null2EmptyStr(claims.get(CommonEnums.MdcKey.DOCKING_SYSTEM_CODE.getName()));

            Object subjectIdsObj = claims.get(CommonEnums.MdcKey.SUBJECT_IDS.getName());
            String subjectIds = null2EmptyStr(subjectIdsObj);
            Object subjectNamesObj = claims.get(CommonEnums.MdcKey.SUBJECT_NAMES.getName());
            String subjectNames = null2EmptyStr(subjectNamesObj);
            Object entAdminFlagObj = claims.get(CommonEnums.MdcKey.ENT_ADMIN_FLAG.getName());
            String entAdminFlag = null2EmptyStr(entAdminFlagObj);

            String origin = claims.get(CommonEnums.MdcKey.ORIGIN.getName()).toString();
            if(!Stringer.isNullOrEmpty(sdeptName)){
                sdeptName = URLDecoder.decode(sdeptName,Stringer.DEFAULT_CHARSET);
            }

            String randomStrRedis = octoToken.getRandomStr();
            if (!randomStr.equals(randomStrRedis)) {
                log.warn("登录token {}被 {} 覆盖", randomStr, randomStrRedis);
                request.setAttribute(CommonEnums.MdcKey.AUTH_CODE.getName(), ErrorCode.RIGHT_OVERRIDE.getStatus());
                return false;
            }
            //TODO... 这个可以在用户端做， 写到配置文件里面。。。 ....localhost:8001,localhost:8080

//            if(!originInToken.toString().equals(origin)){
//                log.warn("origin不对");
//                return false;
//            }

            //数据透传
            Map<String, String> dataMap = new ConcurrentHashMap<>(24);
            dataMap.put(CommonEnums.MdcKey.ORIGIN.getName(), origin);
            dataMap.put(CommonEnums.MdcKey.USEID.getName(), userId);
            dataMap.put(CommonEnums.MdcKey.SCOPE.getName(), scope);
            dataMap.put(CommonEnums.MdcKey.USER_NAME.getName(), userName);
            dataMap.put(CommonEnums.MdcKey.NAME.getName(), name);
            dataMap.put(CommonEnums.MdcKey.DEPT_ID.getName(), deptId);
            dataMap.put(CommonEnums.MdcKey.SUBJECT_TYPE.getName(), subjectType);

            String expertId = claims.get(com.bid.base.common.entity.CommonEnums.MdcKey.EXPERT_ID.getName()).toString();
            dataMap.put(com.bid.base.common.entity.CommonEnums.MdcKey.EXPERT_ID.getName(), expertId);
            dataMap.put(CommonEnums.MdcKey.LEGAL_ID.getName(), legalId);
            dataMap.put(CommonEnums.MdcKey.ZZHLCA_LOGIN_TID.getName(), loginTid);
            dataMap.put(CommonEnums.MdcKey.L_RANDOM_STR.getName(),randomStr);
            dataMap.put(CommonEnums.MdcKey.TOKEN.getName(), token);

            dataMap.put(CommonEnums.MdcKey.CAPACITY_TYPE.getName(), capacityType);
            dataMap.put(CommonEnums.MdcKey.LOGIN_TYPE.getName(), loginType);
            dataMap.put(CommonEnums.MdcKey.SURVEILLANCE_DEPT_CODE.getName(), sdeptCode);
            dataMap.put(CommonEnums.MdcKey.SURVEILLANCE_DEPT_NAME.getName(), sdeptName);
            dataMap.put(CommonEnums.MdcKey.GOV_EXPERT_ID.getName(), govExpertId);

            dataMap.put(CommonEnums.MdcKey.DOCKING_SYSTEM_CODE.getName(), dockingSystemCode);
            dataMap.put(CommonEnums.MdcKey.SUBJECT_IDS.getName(), subjectIds);
            dataMap.put(CommonEnums.MdcKey.SUBJECT_NAMES.getName(), subjectNames);
            dataMap.put(CommonEnums.MdcKey.ENT_ADMIN_FLAG.getName(), entAdminFlag);

            log.info("准备放入mdc的map为：{}", JSONObject.toJSON(dataMap));
            MDC.setContextMap(dataMap);

        } catch (ExpiredJwtException e) {
            log.error("token过期，需要重新登录 {}", e);
            return false;
        } catch (Exception e) {
            log.error("{}", e);
            return false;
        }
        //可以用threadhold 传递到后面
        return true;
    }

    public static String null2EmptyStr(Object obj){
        return Stringer.isNullOrEmpty(obj) ? "" : obj.toString();
    }

    public static Object needRefresh(Claims claims, OctoToken octoToken, BigDecimal warningVlaue, String octoid, String refreshTokenUrl, String sm4Httpkey, RedissonClient redissonClient, String octoRedisPreffix) {
        Object data = null;
        try {
            long now = System.currentTimeMillis();
            Object expireAtMillisObj = claims.get(CommonEnums.MdcKey.EXPIRE_AT_MILLIS.getName());
            Object expireTimeMillisObj = claims.get(CommonEnums.MdcKey.EXPIRE_TIME_MILLIS.getName());
            Object originObj = claims.get(ORIGIN);
            Object legalIdObj = claims.get(CommonEnums.MdcKey.LEGAL_ID.getName());
            Object subjectTypeObj = claims.get(CommonEnums.MdcKey.SUBJECT_TYPE.getName());
            Object deptIdObj = claims.get(CommonEnums.MdcKey.DEPT_ID.getName());
            Object capacityTypeObj = claims.get(CommonEnums.MdcKey.CAPACITY_TYPE.getName());
            Object entAdminFlagObj = claims.get(CommonEnums.MdcKey.ENT_ADMIN_FLAG.getName());


            log.info("expireAtMillisObj：{} ,expireTimeMillisObj: {},originObj123:{}", expireAtMillisObj, expireTimeMillisObj,originObj);
            Long expireAtMillis = Long.valueOf(expireAtMillisObj.toString());
            Long expireTimeMillis = Long.valueOf(expireTimeMillisObj.toString());
            Long nowLevel = expireAtMillis - now;
            BigDecimal top = new BigDecimal(nowLevel);
            BigDecimal bottom = new BigDecimal(expireTimeMillis);

            BigDecimal waterLevel = top.divide(bottom, 2, RoundingMode.HALF_UP);
            log.info("warningVlaue: {}, curr water level {}", warningVlaue, waterLevel);
            if (!(warningVlaue.subtract(waterLevel).compareTo(new BigDecimal("0")) > 0)) {
                log.info("greater than warningVlaue go on");
                return null;
            }
            log.info("less than warningVlaue ");
            /**
             * 刷新token
             * 参考https://developers.weixin.qq.com/doc/offiaccount/OA_Web_Apps/Wechat_webpage_authorization.html#2
             */
            Map<String, String> params = new HashMap<String, String>();
            params.put("octoid", octoid);
            params.put("refresh_token", octoToken.getRefreshToken());
            params.put(AuthAssistant.SUB_SYS, originObj.toString());
            //把里面有的都传递下去
            Set<String> keys = claims.keySet();
            keys.forEach(key->{
                params.put(key,Stringer.null2EmptyStr(claims.get(key)));
            });
//            params.put(CommonEnums.MdcKey.LEGAL_ID.getName(), Stringer.null2EmptyStr(legalIdObj));
//            params.put(CommonEnums.MdcKey.SUBJECT_TYPE.getName(), Stringer.null2EmptyStr(subjectTypeObj));
            //准备升级1.5.7
//            params.put(CommonEnums.MdcKey.DEPT_ID.getName(), Stringer.null2EmptyStr(deptIdObj));
//            params.put(CommonEnums.MdcKey.CAPACITY_TYPE.getName(), Stringer.null2EmptyStr(capacityTypeObj));
//            params.put(CommonEnums.MdcKey.ENT_ADMIN_FLAG.getName(), Stringer.null2EmptyStr(entAdminFlagObj));

            String s = CommonHttp.postEncrypt(refreshTokenUrl, params, sm4Httpkey, null);//(refreshTokenUrl, params);
            log.info("refreseToken:子系统之间的调用返回：{}", s);
            if (Stringer.isNullOrEmpty(s)) {
                throw new RuntimeException("认证中心异常");
            }
            ApiResult apiResult = JSONObject.parseObject(s, ApiResult.class);
            if (!requestSucc(apiResult)) {
                return ApiResult.error("数据异常（子系统之间）");
            }
            Object resData = apiResult.getData();
            OctoSub octoSub = JSONObject.parseObject(resData.toString(), OctoSub.class);
            data = octoSub.getAccessToken();
            //DONE... 从redis中删除原来的token    2. 把新的token刷新进去 先不做把
            //刷新本地的refresh_token,,,,,token不用刷新 因为没存
            saveOctoToke2redis(redissonClient, claims.get(CommonEnums.MdcKey.L_RANDOM_STR.getName()).toString(), octoSub, claims.getIssuer(), octoRedisPreffix);

        } catch (Exception e) {
            log.error("{}", e);
            return null;
        }
        return data;
    }

    //跟新本机的 refresh_token
    public static void saveOctoToke2redis(RedissonClient redissonClient, String randomStr, OctoSub octoSub, String scope, String octoRedisPreffix) {
        String tokenKey = getTokenKeyInRedis(octoSub.getUserId(), scope, octoRedisPreffix);
        OctoToken octoToken = new OctoToken();
        octoToken.setRefreshToken(octoSub.getRefreshToken());
        octoToken.setRandomStr(randomStr);
        log.info("存入redis的值： octoToken {}", JSONObject.toJSON(octoToken));
        RBucket<Object> bucket = redissonClient.getBucket(tokenKey);
        bucket.set(octoToken, octoSub.getExpiresIn() + 5000, TimeUnit.MILLISECONDS);
    }


//    protected String postInSubSys(String url, Map<String, String> paramsMap) {
//        return postInSubSys(url,paramsMap,null);
//    }
//
//    protected String postInSubSys(String url, Map<String, String> paramsMap, Map<String, String> headerMap) {
//        return CommonHttp.postEncrypt(url,paramsMap,sm4Httpkey,headerMap);
//    }

    public static Method getMethod(ProceedingJoinPoint joinPoint) throws Throwable {
        MethodInvocationProceedingJoinPoint methodPoint = (MethodInvocationProceedingJoinPoint) joinPoint;
        Field proxy = methodPoint.getClass().getDeclaredField("methodInvocation");
        proxy.setAccessible(true);
        ReflectiveMethodInvocation j = (ReflectiveMethodInvocation) proxy.get(methodPoint);
        return j.getMethod();
    }


    public static Object getLocalOctoToken(RedissonClient redissonClient, String userId, String scope, String octoRedisPreffix) {
        String tokenKey = getTokenKeyInRedis(userId, scope, octoRedisPreffix);
        RBucket<Object> bucket = redissonClient.getBucket(tokenKey);
        return bucket.get();
    }

    public static void clearLocalOctoToken(RedissonClient redissonClient, String userId, String scope, String octoRedisPreffix) {
        String tokenKey = getTokenKeyInRedis(userId, scope, octoRedisPreffix);
        RBucket<Object> bucket = redissonClient.getBucket(tokenKey);
        boolean delete = bucket.delete();
        log.info("清除key： {} 的结果是： {}", tokenKey, delete);
    }

    /** 缓存用户的 key   改C#的时候  */
    public static String getUserKey(String userName, String octoRedisPreffix) {
        return octoRedisPreffix + "_USER_" + userName;
    }
    /** 缓存REGISTER key   改C#的时候  */
    public static String getOctoIdKey(String redisPreffix,String octoid) {
        return redisPreffix + "_OCTOID_REGISTER_" + octoid;
    }

    public static void clearUserByLoadCallback(RedissonClient redissonClient, CacheTemplateService cacheService, String account, String octoRedisPreffix) {
        String key = getUserKey(account, octoRedisPreffix);
        cacheService.clearCache(redissonClient, key);
    }





    public static String getTokenKeyInRedis(String userId, String scope, String octoRedisPreffix) {
        String key = octoRedisPreffix + "_" + userId + "_" + scope;
//        log.info("获取d token的key是： {} ", key);
        return key;
    }
}
